package com.wdl.datarest.implementation;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.wdl.datarest.data.Alarm;
import com.wdl.datarest.data.AlarmRepository;
import com.wdl.datarest.data.AlarmType;
import com.wdl.datarest.data.Person;
import com.wdl.datarest.data.PersonRepository;
import com.wdl.datarest.data.SleepMode;

@Component
public class ScheduledTaskController {
    private static Logger log = LoggerFactory.getLogger("ScheduledTaskController");

    @Autowired
    private DevCnfgCache cache;

    @Autowired
    private AlarmRepository alarmRepo;

    @Autowired
    private PersonRepository personRepo;

    private void hourTask(CacheData data) {
        long personId = data.getPersonId();
        if (personId <= 0) {
            log.error("Person Id is 0 for device: " + data.getDeviceId());
            return;
        }

        if (data.getHeartTotal() > 0) {
            LogUtils.logHeartHistData(personId, System.currentTimeMillis(), data.getHeartSum() / data.getHeartTotal());
        }
        data.resetHeart();

        if (data.getBreatheTotal() > 0) {
            LogUtils.logBreatheHistData(personId, System.currentTimeMillis(), data.getBreatheSum() / data.getBreatheTotal());
        }
        data.resetBreathe();

        LogUtils.logMoveHistPerHour(personId, System.currentTimeMillis(), data.getMoveTotal());
        data.resetMoveTotal();
    }

    private void dailyTaskAt8Am(CacheData data) {
        long personId = data.getPersonId();
        if (personId <= 0) {
            log.error("Person Id is 0 for device: " + data.getDeviceId());
            return;
        }

        short deepSleep = data.calDeepSleepInSeconds();
        short shallowSleep = data.calShallowSleepInSeconds();
        if (deepSleep != 0 || shallowSleep != 0) {
            LogUtils.logSleepStatus(personId, System.currentTimeMillis(), deepSleep, shallowSleep);
        }
    }

    private void dailyTaskAt8Pm(CacheData data) {
        data.setSleepModeStartingTime(System.currentTimeMillis());
        data.setDeepSleepInSeconds((short) 0);
        data.setShallowSleepInSeconds((short) 0);
    }

    private void clearAgingAlarm() {
        int total = 0;
        int nonAcked = 0;
        long maxTime = System.currentTimeMillis() - 30 * 24 * 60 * 60 * 1000;
        for (Alarm alarm : alarmRepo.findAll()) {
            if (alarm.getRaisedTime() < maxTime) {
                total++;

                if (alarm.getAckedTime() < 2) {
                    nonAcked++;
                    clearNonAckedAlarmFromPerson(alarm);
                    LogUtils.logNonAckedAlarm(alarm);
                }

                alarmRepo.delete(alarm);
            }
        }

        log.info("clearingAgingAlarm: total " + total + " alarms were cleared, " + nonAcked + " of them are non-acked alarms.");
    }

    private void clearNonAckedAlarmFromPerson(Alarm alarm) {
        long personId = alarm.getPersonId();
        Person person = personRepo.findByIndex(personId);
        if (person == null) {
            return;
        }

        long alarmId = alarm.getId();
        switch(alarm.getType()) {
        case HEART:
            if (alarmId == person.getHeartAlarmId()) {
                person.setHeartAlarmId(0);
                person.setHeartAlarmFlag(false);
                person.setHideHeartAlarm(false);
            }
            break;
        case BREATHE:
            if (alarmId == person.getBreatheAlarmId()) {
                person.setBreatheAlarmId(0);
                person.setBreatheAlarmFlag(false);
                person.setHideBreatheAlarm(false);
            }
            break;
        case UP:
            if (alarmId == person.getUpAlarmId()) {
                person.setUpAlarmId(0);
                person.setUpAlarmFlag(false);
                person.setHideUpAlarm(false);
            }
            break;
        case SIDE:
            if (alarmId == person.getSideAlarmId()) {
                person.setSideAlarmId(0);
                person.setSideAlarmFlag(false);
                person.setHideSideAlarm(false);
            }
            break;
        case AWAY:
            if (alarmId == person.getAwayAlarmId()) {
                person.setAwayAlarmId(0);
                person.setAwayAlarmFlag(false);
                person.setHideAwayAlarm(false);
            }
            break;
        case WET:
            if (alarmId == person.getWetAlarmId()) {
                person.setWetAlarmId(0);
                person.setWetAlarmFlag(false);
                person.setHideWetAlarm(false);
            }
            break;
        case MOVE: 
            if (alarmId == person.getMoveAlarmId()) {
                person.setMoveAlarmId(0);
                person.setMoveAlarmFlag(false);
                person.setHideMoveAlarm(false);
            }
            break;
        case DEVICE:
            if (alarmId == person.getDeviceAlarmId()) {
                person.setDeviceAlarmId(0);
                person.setDeviceAlarmFlag(false);
                person.setHideDeviceAlarm(false);
            }
            break;
        case RING:
            if (alarmId == person.getRingAlarmId()) {
                person.setRingAlarmId(0);
                person.setRingAlarmFlag(false);
                person.setHideRingAlarm(false);
            }
            break;
        case LEFT:
            if (alarmId == person.getLeftAlarmId()) {
                person.setLeftAlarmId(0);
                person.setLeftAlarmFlag(false);
                person.setHideLeftAlarm(false);
            }
            break;
        case RIGHT:
            if (alarmId == person.getRightAlarmId()) {
                person.setRightAlarmId(0);
                person.setRightAlarmFlag(false);
                person.setHideRightAlarm(false);
            }
            break;
        default:
            break;
        }

        personRepo.save(person);
    }

    private void checkDeviceAlarm(CacheData data) {
        long personId = data.getPersonId();
        if (personId <= 0) {
            log.error("Person Id is 0 for device: " + data.getDeviceId());
            return;
        }

        Person person = personRepo.findByIndex(personId);
        long currentTime = System.currentTimeMillis();
        long timeDiff = currentTime - data.getDeviceUpdateTime();

        if (person == null) {
            log.error("checkDeviceAlarm: Failed to find personId " + personId + " from DB. Ignore request.");
            return;
        }

        // If more than 5mins no data comes to device report connection lost alarm
        if (timeDiff > 1000 * 60 * 5) {
            // If device is already connection lost do not report more alarm
            if (person.isDeviceAlarmFlag()) {
                return;
            }

            Alarm alarmConnLost = new Alarm();
            alarmConnLost.setRaisedTime(currentTime);
            alarmConnLost.setPersonId(personId);
            alarmConnLost.setDeviceId(data.getDeviceId());
            alarmConnLost.setValue((short)timeDiff);
            alarmConnLost.setInstitutionId(person.getInstitution() == null ? 1 : person.getInstitution().getId());
            alarmConnLost.setPersonName(person.getPersonName());
            alarmConnLost.setType(AlarmType.DEVICE);
            Alarm savedAlarm = alarmRepo.save(alarmConnLost);

            person.setDeviceAlarmFlag(true);
            person.setHideDeviceAlarm(false);
            person.setDeviceAlarmId(savedAlarm.getId());
            
            // Clear all other alarms if device is offline
            if (person.isLeftAlarmFlag()) {
                person.setLeftAlarmFlag(false);
                person.setHideLeftAlarm(false);
                acknowledgeAlarm(person, AlarmType.LEFT);
            }

            if (person.isRightAlarmFlag()) {
                person.setRightAlarmFlag(false);
                person.setHideRightAlarm(false);
                acknowledgeAlarm(person, AlarmType.RIGHT);
            }

            if (person.isHeartAlarmFlag()) {
                person.setHeartAlarmFlag(false);
                person.setHideHeartAlarm(false);
                acknowledgeAlarm(person, AlarmType.HEART);
            }

            if (person.isBreatheAlarmFlag()) {
                person.setBreatheAlarmFlag(false);
                person.setHideBreatheAlarm(false);
                acknowledgeAlarm(person, AlarmType.BREATHE);
            }

            if (person.isRingAlarmFlag()) {
                person.setRingAlarmFlag(false);
                person.setHideRingAlarm(false);
                acknowledgeAlarm(person, AlarmType.RING);
            }

            if (person.isTurnOverReminderAlarmFlag()) {
                person.setTurnOverReminderAlarmFlag(false);
                acknowledgeAlarm(person, AlarmType.TURN_OVER);
            }
            
            if (person.isWetAlarmFlag()) {
	            person.setWetAlarmFlag(false);
	            person.setHideWetAlarm(false);
                acknowledgeAlarm(person, AlarmType.WET);
            }

            if (person.isUpAlarmFlag()) {
                person.setUpAlarmFlag(false);
                person.setHideUpAlarm(false);
                acknowledgeAlarm(person, AlarmType.UP);
            }
            
            if (person.isSideAlarmFlag()) {
	            person.setSideAlarmFlag(false);
	            person.setHideSideAlarm(false);
	            acknowledgeAlarm(person, AlarmType.SIDE);
            }

            if (person.isAwayAlarmFlag()) {
	            person.setAwayAlarmFlag(false);
	            person.setHideAwayAlarm(false);
                acknowledgeAlarm(person, AlarmType.AWAY);
            }
            
            if (person.isMoveAlarmFlag()) {
	            person.setMoveAlarmFlag(false);
	            person.setHideMoveAlarm(false);
                acknowledgeAlarm(person, AlarmType.MOVE);
            }
            
            personRepo.save(person);
        } else {
            if (!person.isDeviceAlarmFlag()) {
                return;
            }

            // Ack existing link lost alarm
            long alarmId = person.getDeviceAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setDeviceAlarmId(0);
            }

            // Clear device alarm flag in person table
            person.setDeviceAlarmFlag(false);
            person.setHideDeviceAlarm(false);
            personRepo.save(person);
        }
    }

    /**
     * Every hour task to log breathe, heartbeat and move to elasticsearch.
     */
    // second minute hour day month year
    @Scheduled(cron="0 0 * * * *")
    private void elkHourTask1() {
        log.info("Hourly task 1 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 0) {
                continue;
            }
            try {
                total++;
                hourTask(device);
            } catch (Exception e) {}
        }
        log.info("Hourly task 1 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 * * * *")
    private void elkHourTask2() {
        log.info("Hourly task 2 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 1) {
                continue;
            }
            try {
                total++;
                hourTask(device);
            } catch (Exception e) {}
        }
        log.info("Hourly task 2 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 * * * *")
    private void elkHourTask3() {
        log.info("Hourly task 3 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 2) {
                continue;
            }
            try {
                total++;
                hourTask(device);
            } catch (Exception e) {}
        }
        log.info("Hourly task 3 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 * * * *")
    private void elkHourTask4() {
        log.info("Hourly task 4 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 3) {
                continue;
            }
            try {
                total++;
                hourTask(device);
            } catch (Exception e) {}
        }
        log.info("Hourly task 4 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 * * * *")
    private void elkHourTask5() {
        log.info("Hourly task 5 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 4) {
                continue;
            }
            try {
                total++;
                hourTask(device);
            } catch (Exception e) {}
        }
        log.info("Hourly task 5 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    /**
     * Log sleep data to elasticsearch every day at 8:00:00
     */
    @Scheduled(cron="0 0 8 * * *")
    private void elkDailyTask1() {
        log.info("Daily task 1 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 0) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Am(device);
            } catch (Exception e) {}
        }
        log.info("Daily task 1 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 8 * * *")
    private void elkDailyTask2() {
        log.info("Daily task 2 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 1) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Am(device);
            } catch (Exception e) {}
        }
        log.info("Daily task 2 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 8 * * *")
    private void elkDailyTask3() {
        log.info("Daily task 3 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 2) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Am(device);
            } catch (Exception e) {}
        }
        log.info("Daily task 3 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 8 * * *")
    private void elkDailyTask4() {
        log.info("Daily task 4 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 3) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Am(device);
            } catch (Exception e) {}
        }
        log.info("Daily task 4 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 8 * * *")
    private void elkDailyTask5() {
        log.info("Daily task 5 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 4) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Am(device);
            } catch (Exception e) {}
        }
        log.info("Daily task 5 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    /**
     * Clear sleep data every day at 20:00:00
     */
    @Scheduled(cron="0 0 20 * * *")
    private void elkDailyClearTask1() {
        log.info("Daily sleep data clear task 1 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 0) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Pm(device);
            } catch (Exception e) {}
        }
        log.info("Daily sleep data clear task 1 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 20 * * *")
    private void elkDailyClearTask2() {
        log.info("Daily sleep data clear task 2 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 1) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Pm(device);
            } catch (Exception e) {}
        }
        log.info("Daily sleep data clear task 2 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 20 * * *")
    private void elkDailyClearTask3() {
        log.info("Daily sleep data clear task 3 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 2) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Pm(device);
            } catch (Exception e) {}
        }
        log.info("Daily sleep data clear task 3 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 20 * * *")
    private void elkDailyClearTask4() {
        log.info("Daily sleep data clear task 4 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 3) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Pm(device);
            } catch (Exception e) {}
        }
        log.info("Daily sleep data clear task 4 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    @Scheduled(cron="0 0 20 * * *")
    private void elkDailyClearTask5() {
        log.info("Daily sleep data clear task 5 starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        for (CacheData device : cache.getCfgCaches()) {
            long deviceId = device.getDeviceIndex();
            if (deviceId % 5 != 4) {
                continue;
            }
            try {
                total++;
                dailyTaskAt8Pm(device);
            } catch (Exception e) {}
        }
        log.info("Daily sleep data clear task 5 finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }

    /**
     * Audit device cache every day at 1:00 am.
     */
    @Scheduled(cron="0 0 1 * * *")
    private void cacheAuditTask() {
        log.info("Daily cache audit task starts to execute.");
        long startTime = System.currentTimeMillis();
        try {
            cache.cacheAudit();
        } catch (Exception e) {}
        log.info("Daily cache audit task finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds.");
    }

    /**
     * Aging alarm (raised time is one month ago) clearing task every day at 2:00 am.
     */
    @Scheduled(cron="0 0 2 * * *")
    private void alarmClearingTask() {
        log.info("Daily aging alarm clearing task starts to execute.");
        long startTime = System.currentTimeMillis();
        try {
            clearAgingAlarm();
        } catch (Exception e) {}
        log.info("Daily aging alarm clearing task finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds.");
    }

    /**
     * Check device alarm every 2 minutes.
     */
    @Scheduled(fixedRate = 2 * 60 * 1000)
    private void deviceAlarmTask() {
        log.info("Device alarm task starts to execute.");
        int total = 0;
        long startTime = System.currentTimeMillis();
        try {
            for (CacheData device : cache.getCfgCaches()) {
                total++;
                checkDeviceAlarm(device);
            }
        } catch (Exception e) {}
        log.info("Device alarm task finished, took " + (System.currentTimeMillis() - startTime)/1000 + " seconds, processed " + total);
    }
    
    private void acknowledgeAlarm(Person person, AlarmType type) {
        long alarmId = 0;

        switch(type) {
        case HEART:
            alarmId = person.getHeartAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setHeartAlarmId(0);
            }
            break;
        case BREATHE:
            alarmId = person.getBreatheAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setBreatheAlarmId(0);
            }
            break;
        case UP:
            alarmId = person.getUpAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setUpAlarmId(0);
            }
            break;
        case SIDE:
            alarmId = person.getSideAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setSideAlarmId(0);
            }
            break;
        case AWAY:
            alarmId = person.getAwayAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setAwayAlarmId(0);
            }
            break;
        case WET:
            alarmId = person.getWetAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setWetAlarmId(0);
            }
            break;
        case MOVE: 
            alarmId = person.getMoveAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setMoveAlarmId(0);
            }
            break;
        case DEVICE:
            alarmId = person.getDeviceAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setDeviceAlarmId(0);
            }
            break;
        case RING:
            alarmId = person.getRingAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setRingAlarmId(0);
            }
            break;
        case TURN_OVER:
            alarmId = person.getTurnOverReminderAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setTurnOverReminderAlarmId(0);
            }

            // check if need to schedule next reminder
            if (person.getTurnOverReminder() > 0 && person.getCheckoutTime() <= 0 && person.getDevice1() > 0) {
                CacheData cacheData = cache.getCnfgDataFromCacheByPersonId(person.getId());
                if (cacheData == null) {
                    log.error("CacheData is null for personName=" + person.getPersonName() + " while acking turn over alarm.");
                } else {
                    log.info("Schedule turn over reminder fo personName=" + person.getPersonName() + ", interval=" + person.getTurnOverReminder() + " minutes.");
                    cache.scheduleTurnOverReminder(person.getId(), person.getTurnOverReminder());
                    cacheData.setSentReminder(true);
                }
            }
            break;
        case LEFT:
            alarmId = person.getLeftAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setLeftAlarmId(0);
            }
            break;
        case RIGHT:
            alarmId = person.getRightAlarmId();
            if (alarmId > 0) {
                Alarm alarm = alarmRepo.findByIndex(alarmId);
                if (alarm != null) {
                    alarm.setAckedTime(System.currentTimeMillis());
                    alarmRepo.save(alarm);
                    LogUtils.logAlarm(alarm);
                }
                person.setRightAlarmId(0);
            }
            break;
        default:
            break;
        }
    }
}